/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.acworks.acroute.impl;

import com.acworks.acroute.Datacenter;
import com.acworks.acroute.Route;
import com.acworks.acroute.Space;
import com.acworks.acroute.SpaceType;
import com.acworks.acroute.Util;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author nikita
 */
public class RouteImpl implements Route {

    private final List<Space> routeSpaces;
    private final Datacenter datacenter;
    private Space currentSpace; //this variable isn't really needed

    public RouteImpl(Datacenter dc) {
        assert dc != null;
        this.datacenter = dc;
        routeSpaces = new ArrayList<Space>();
        currentSpace = dc.getStartingSpace();
    }

    /**
     * create a Route that branches off existing route, advancing to 'nextRoom'
     * @param r
     * @param nextRoom
     */
    public RouteImpl(Route r, int spaceSublistCount, Space nextRoom) {
        assert r != null;
        assert nextRoom != null;
        assert spaceSublistCount >= 0;

        datacenter = r.getDatacenter();
        routeSpaces = new ArrayList<Space>(r.getRouteSpaces().subList(0, spaceSublistCount));
        currentSpace = r.getCurrentSpace();
        advanceToSpace(nextRoom);
    }

    @Override
    public List<Space> getRouteSpaces() {
        return routeSpaces;
    }

    @Override
    public void advanceToSpace(Space space) {
        assert space != null;

        if (canAdvanceToSpace(space)) {
            routeSpaces.add(space);
            currentSpace = space;
        } else {
            throw new IllegalStateException(this + " cannot be advanced to space " + space);
        }
    }

    @Override
    public boolean canAdvanceToSpace(Space space) {
        assert space != null;

        //our room?
        if (space.getSpaceType() != SpaceType.OWNED_ROOM) {
            return false;
        }

        //already visited?
        if (getRouteSpaces().contains(space)) {
            return false;
        }

        return true;
    }

    @Override
    public boolean isTerminated() {
        return getAdjacentUnvisitedOwnedRooms().isEmpty();
    }

    @Override
    public boolean isValid() {

        final List<Space> route = getRouteSpaces();
        final Space lastSpaceInRoute = route.size() > 0 ? route.get(route.size() - 1) : null;

        return lastSpaceInRoute != null && datacenter.getOwnedRoomsCount() == routeSpaces.size() &&
                !Util.findSpacesByType(getDatacenter().getSpacesAdjacentTo(lastSpaceInRoute), SpaceType.END_SPACE).isEmpty();
    }

    @Override
    public Datacenter getDatacenter() {
        return datacenter;
    }

    @Override
    public Space getCurrentSpace() {
        assert currentSpace != null;
        return currentSpace;
    }

    @Override
    public List<Space> getAdjacentUnvisitedOwnedRooms() {
        Space cs = getCurrentSpace();
        List<Space> unvisitedOwnedRooms = new ArrayList<Space>(4);
        for (Space adjacentSpace : datacenter.getSpacesAdjacentTo(cs)) {
            if (adjacentSpace.getSpaceType() == SpaceType.OWNED_ROOM && (!routeSpaces.contains(adjacentSpace))) {
                unvisitedOwnedRooms.add(adjacentSpace);
            }
        }
        return unvisitedOwnedRooms;
    }
}
